import copy

import pandas as pd
import numpy as np
import random
RoadStack = [3, 4, 5, 6]
TaskCount = 10
# 存在问题：在放置任务中，可能出现某些二层不存在货位

class ContainerLocation:
    ContainerList = {}

    def __init__(self, bay, stack, level, state, Locationtype):
        self.bay = bay  # 贝位
        self.level = level  # 层位
        self.stack = stack  # 栈位
        self.state = state  # 集装箱箱位状态: 放置货物 1 没有货物 0
        self.Locationtype = Locationtype  # 箱位类型: 0 普通箱位 1 道路箱位
        ContainerLocation.ContainerList[(stack, bay, level)] = self

    # 根据箱位号查询箱位对象列表
    @classmethod
    def FindContainerLocation(cls, bay, stack, level):
        try:
            return cls.ContainerList[(stack, bay, level)]
        except KeyError:
            return False

class TaskAllocation:
    def __init__(self,TaskCount,ContainerLocationMatrix):
        self.TaskCount = TaskCount
        self.ContainerLocationMatrix = ContainerLocationMatrix
        self.ContainerCountMatrix = ContainerLocationMatrix[0]+ContainerLocationMatrix[1]

    def RomdomTask(self,TaskCount):
        ReachStackerCanPick = True
        ReachStackerCanPut = True
        ReachStackerCanWorkTaskList = []
        CraneCanWorkTaskList = []
        Sigle = []
        Double = []
        TaskList = dict()
        while True:
            # 随机生成一个抓取任务
            self.ContainerCountMatrix = ContainerLocationMatrix[0] + ContainerLocationMatrix[1]
            CanPickCondition = self.ContainerCountMatrix >= 1
            Canpickindices = np.argwhere(CanPickCondition)
            PickLoc = random.choices(Canpickindices).pop()
            PickLocObj = ContainerLocation.FindContainerLocation(PickLoc[1]+1,PickLoc[0]+1,self.ContainerCountMatrix[PickLoc[0]][PickLoc[1]])
            if PickLocObj is False:
                continue
            TaskList["StartPosition"] = [PickLoc[1] + 1, PickLoc[0] + 1,self.ContainerCountMatrix[PickLoc[0]][PickLoc[1]]]

            # 首先根据该抓取任务的位置，判断任务类型
            # 若该抓取任务的抓取位置处于道路栈位，则该任务为存储任务
            if PickLoc[0] in [4,5,12,13]:
                # 随机选择一个放置箱位
                while True:
                    CanPutCondition = self.ContainerCountMatrix <= 1
                    Canpickindices = np.argwhere(CanPutCondition)
                    Putloc = random.choice(Canpickindices)
                    PutLocObj = ContainerLocation.FindContainerLocation(Putloc[1] + 1, Putloc[0] + 1,
                                                                     self.ContainerCountMatrix[Putloc[0]][Putloc[1]]+1)
                    if PutLocObj is False:
                        continue
                    if np.array_equal(PickLoc,Putloc) == False:
                        break
                # 将任务放置到任务列表中
                TaskList["EndPosition"] = [Putloc[1]+1,Putloc[0]+1,self.ContainerCountMatrix[Putloc[0]][Putloc[1]]+1]
            # 若该抓取任务的抓取位置处于普通栈位，则该任务为取箱任务
            if PickLoc[0] in [0,1,6,7,8,9,10,11]:
                if PickLoc[0] in [0,1]:
                    TaskList["EndPosition"] = [PickLoc[1]+1,6,1]
                if PickLoc[0] in [6,7,8,9,10,11]:
                    TaskList["EndPosition"] = [PickLoc[1]+1,random.choice([6,13]),1]
            # 若该抓取任务的抓取位置处于列车装卸线栈位，根据随机数生成任务
            if PickLoc[0] in [2,3]:
                # 生成一个随机数
                randomnum = random.random()
                # 若随机数小于0.5，则生成一个存储任务
                if randomnum < 0.7:
                    while True:
                        CanPutCondition = self.ContainerCountMatrix <= 1
                        Canpickindices = np.argwhere(CanPutCondition)
                        Putloc = random.choice(Canpickindices)
                        PutLocObj = ContainerLocation.FindContainerLocation(Putloc[1] + 1, Putloc[0] + 1,
                                                                            self.ContainerCountMatrix[Putloc[0]][
                                                                                Putloc[1]] + 1)
                        if PutLocObj is False:
                            continue
                        if np.array_equal(PickLoc, Putloc) == False:
                            break
                    TaskList["EndPosition"] = [Putloc[1]+1,Putloc[0]+1,self.ContainerCountMatrix[Putloc[0]][Putloc[1]]+1]
                # 若随机数大于0.5，则生成一个取箱任务
                else:
                    if PickLoc[0] == 2:
                        TaskList["EndPosition"] = [PickLoc[1]+1,6,1]
                    if PickLoc[0] == 3:
                        TaskList["EndPosition"] = [PickLoc[1]+1,random.choice([6,13]),1]
            # 判断该任务正面吊是否能够进行作业
            if TaskList["StartPosition"][1] <= 3 or TaskList["EndPosition"][1] <= 3:
                ReachStackerCanPick = False
            else:
                PickContainerLoc = TaskList["StartPosition"]
                # 计算抓取箱位上下栈占用情况
                DownStackData = self.ContainerCountMatrix[4:PickContainerLoc[1]-1, PickContainerLoc[0]-1]
                DownStackData = DownStackData[::-1]
                UpStackData = self.ContainerCountMatrix[PickContainerLoc[1]:14, PickContainerLoc[0]-1]
                # 判断正面吊是否能够到达抓取位置
                if np.count_nonzero(UpStackData) == 0 or np.count_nonzero(DownStackData) == 0:
                    ReachStackerCanPick = True
                elif(np.count_nonzero(UpStackData) == 1 and
                     UpStackData[0] <= self.ContainerCountMatrix[PickContainerLoc[1]-1][PickContainerLoc[0]-1] and UpStackData[0] !=0) or \
                    (np.count_nonzero(DownStackData) == 1 and
                    DownStackData[0] <= self.ContainerCountMatrix[PickContainerLoc[1]-1][PickContainerLoc[0]-1] and DownStackData[0]!=0):
                    ReachStackerCanPick = True
                else:
                    ReachStackerCanPick = False
                PutContainerLoc = TaskList["EndPosition"]
                # 计算放置箱位上下栈占用情况
                DownStackData = self.ContainerCountMatrix[4:PickContainerLoc[1]-1, PickContainerLoc[0]-1]
                DownStackData = DownStackData[::-1]
                UpStackData = self.ContainerCountMatrix[PickContainerLoc[1]:14, PickContainerLoc[0]-1]
                # 判断正面吊是否能够到达放置位置
                if np.count_nonzero(UpStackData) == 0 or np.count_nonzero(DownStackData) == 0:
                    ReachStackerCanPut = True
                elif(np.count_nonzero(UpStackData) == 1 and
                     UpStackData[0] <= self.ContainerCountMatrix[PickContainerLoc[1]-1][PickContainerLoc[0]-1] and UpStackData[0] !=0) or \
                    (np.count_nonzero(DownStackData) == 1 and
                    DownStackData[0] <= self.ContainerCountMatrix[PickContainerLoc[1]-1][PickContainerLoc[0]-1] and DownStackData[0]!=0):
                    ReachStackerCanPut = True
                else:
                    ReachStackerCanPut = False
            if ReachStackerCanPick and ReachStackerCanPut:
                ReachStackerCanWork = True
            else:
                ReachStackerCanWork = False
            # 判断该任务轨道吊是否能够进行作业
            if TaskList["StartPosition"][1] >= 13 or TaskList["EndPosition"][1] >= 13:
                CraneCanWork = False
            else:
                CraneCanWork = True
            if ReachStackerCanWork or CraneCanWork:
                # 如果抓取点的任务不属于道路栈位
                if TaskList["StartPosition"][1]-1 not in [4,5,12,13]:
                    # 更新抓取点的箱位状态
                    self.ContainerLocationMatrix[TaskList["StartPosition"][2]-1][TaskList["StartPosition"][1]-1][TaskList["StartPosition"][0]-1] = 0
                # 如果放置点的任务不属于道路栈位
                if TaskList["EndPosition"][1]-1 not in [4,5,12,13]:
                    # 更新放置点的箱位状态
                    self.ContainerLocationMatrix[TaskList["EndPosition"][2]-1][TaskList["EndPosition"][1]-1][TaskList["EndPosition"][0]-1] = 1
                if ReachStackerCanWork:
                    ReachStackerCanWorkTaskList.append(copy.deepcopy(TaskList))
                if CraneCanWork:
                    CraneCanWorkTaskList.append(copy.deepcopy(TaskList))
                TaskList.clear()
            else:
                continue
            unique_list = []
            for d in ReachStackerCanWorkTaskList+CraneCanWorkTaskList:
                if d not in unique_list:
                    unique_list.append(d)
            if len(unique_list) == TaskCount:
                return [ReachStackerCanWorkTaskList,CraneCanWorkTaskList]




if __name__ == "__main__":
    SigleTask = []
    doubleTask = []
    # 定义可取箱位列表
    ContainerLocationListCanPick = []
    # 定义可放箱位列表
    ContainerLocationListCanPut = []
    # 三维矩阵
    ContainerLocationMatrix = np.zeros((2, 14, 66), dtype=int)
    # 读取箱位状态表
    ContainerLocationTable = pd.read_excel("箱位状态表(20240325目前可用).xlsx")
    for index, row in ContainerLocationTable.iterrows():
        ContainerLocation(stack=row["栈位"], bay=row["贝位"], level=row["层位"], state=row["占用状态"],
                          Locationtype=row["位置类型"])
        ContainerLocationMatrix[row["层位"]-1, row["栈位"]-1, row["贝位"]-1] = row["占用状态"]
    TaskAllocation_ = TaskAllocation(2,ContainerLocationMatrix)
    Task = TaskAllocation_.RomdomTask(TaskCount)
    ReachStackerCanWorkTaskList_ = Task[0]
    CraneCanWorkTaskList_ = Task[1]
    Task = Task[0]+Task[1]
    unique_list = []
    for d in Task:
        if d not in unique_list:
            unique_list.append(d)
    print(unique_list)
    CraneTaskListShow = []
    ReachStackerTaskListShow = []
    for elem in unique_list:
        if elem in ReachStackerCanWorkTaskList_ and elem in CraneCanWorkTaskList_:
            if elem["StartPosition"][0] >= 33 and elem["EndPosition"][0] >= 33:
                CraneTaskListShow.append(elem)
            elif elem["StartPosition"][0] <= 33 and elem["EndPosition"][0] <= 33:
                ReachStackerTaskListShow.append(elem)
            else:
                randomnum = random.random()
                if randomnum < 0.5:
                    ReachStackerTaskListShow.append(elem)
                else:
                    CraneTaskListShow.append(elem)
        if elem in ReachStackerCanWorkTaskList_ and elem not in CraneCanWorkTaskList_:
            ReachStackerTaskListShow.append(elem)
        if elem not in ReachStackerCanWorkTaskList_ and elem in CraneCanWorkTaskList_:
            CraneTaskListShow.append(elem)
    ReachStackerTaskListShow.sort(key=lambda x: x["StartPosition"][0],reverse=False)
    CraneTaskListShow.sort(key=lambda x: x["StartPosition"][0],reverse=True)
    print("正面吊任务列表:{}".format(ReachStackerTaskListShow))
    print("轨道吊任务列表:{}".format(CraneTaskListShow))

